﻿#region Disclaimer/Info
///////////////////////////////////////////////////////////////////////////////////////////////////
// MetaCollection
// 
// MetaCollection is a system to provide a standard structure, permissions and metadata service
// for content organization.
//
// This project is hosted at Google Code at http://code.google.com/p/metacollection/
//
// This project is licensed under the BSD license.  See the License.txt file for more information.
///////////////////////////////////////////////////////////////////////////////////////////////////
#endregion

using System;
using System.Linq;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;

namespace MetaCollection.Framework.Model
{

	/// <summary>
	/// Instance of an item.  Represents an aggregate of several sub-domain objects in a single record.
	/// 
	/// An ItemInstance is the base of all types of Item Models in the collection.  The different item models
	/// are given shape (required properties, etc) through IProviders specifically a ResourceProvider.
	/// A ResourceProvider can be configured to validate ItemInstances on save as well as determine unique
	/// persistence requirements.
	/// </summary>
	public interface IItemInstance
	{
		/// <summary>
		/// Unique Identifier of this Item
		/// </summary>
		Guid Id { get; set; }
		/// <summary>
		/// External Identifier associated with this item record
		/// </summary>
		string ExternalId { get; set; }
		/// <summary>
		/// The Unique Identifier of the Parent of this Item
		/// </summary>
		Guid ParentId { get; set; }
		/// <summary>
		/// Version number of this item
		/// </summary>
		int Version { get; set; }
		/// <summary>
		/// Parent version this instance was derived from
		/// </summary>
		int? LeftVersion { get; set; }
		/// <summary>
		/// Optional additional parent version this instance was derived from
		/// </summary>
		int? RightVersion { get; set; }
		/// <summary>
		/// An identifier that denotes who created this version.  Typically
		/// this would be the Principal.Identity.Name
		/// </summary>
		string CreatedBy { get; set; }
		/// <summary>
		/// An optional comment given when this version was created.
		/// </summary>
		string Comment { get; set; }
		/// <summary>
		/// Name Identifier as represented in a structure URI segment
		/// </summary>
		string Name { get; set; }
		/// <summary>
		/// Indicates this item represents a published copy
		/// </summary>
		bool Published { get; set; }
		/// <summary>
		/// MIME Type of this item.
		/// </summary>
		string MimeType { get; set; }
		/// <summary>
		/// Item Specification for this item.
		/// </summary>
		Guid Specification { get; set; }
		/// <summary>
		/// Last modified date/time
		/// </summary>
		DateTime LastModified { get; set; }
		/// <summary>
		/// Href for item path
		/// </summary>
		Uri Href { get; set; }
		/// <summary>
		/// Uniquely identifies a set of security claims for the item.
		/// </summary>
		Guid ItemClaimId { get; set; }
		/// <summary>
		/// Additional item properties
		/// </summary>
		IEnumerable<IItemProperty> Properties { get; set; }
		/// <summary>
		/// Item Access List Entries
		/// </summary>
		IEnumerable<IItemClaim> AccessClaims { get; set; }
		/// <summary>
		/// Relationships owned by this item
		/// </summary>
		IEnumerable<IItemRelationship> Relationships { get; set; }
	}

	/// <summary>
	/// A structure representing an ItemInstance
	/// </summary>
	[Serializable()]
	public struct ItemInstance : IItemInstance
	{
		/// <summary>
		/// Unique Identifier of this Item
		/// </summary>
		public Guid Id { get; set; }
		/// <summary>
		/// External Identifier associated with this item record
		/// </summary>
		public string ExternalId { get; set; }
		/// <summary>
		/// The Unique Identifier of the Parent of this Item
		/// </summary>
		public Guid ParentId { get; set; }
		/// <summary>
		/// Version number of this item
		/// </summary>
		public int Version { get; set; }
		/// <summary>
		/// Parent version this instance was derived from
		/// </summary>
		public int? LeftVersion { get; set; }
		/// <summary>
		/// Optional additional parent version this instance was derived from
		/// </summary>
		public int? RightVersion { get; set; }
		/// <summary>
		/// An identifier that denotes who created this version.  Typically
		/// this would be the Principal.Identity.Name
		/// </summary>
		public string CreatedBy { get; set; }
		/// <summary>
		/// An optional comment given when this version was created.
		/// </summary>
		public string Comment { get; set; }
		/// <summary>
		/// Name Identifier as represented in a structure URI segment
		/// </summary>
		public string Name { get; set; }
		/// <summary>
		/// Indicates this item represents a published copy
		/// </summary>
		public bool Published { get; set; }
		/// <summary>
		/// MIME Type of this item.
		/// </summary>
		public string MimeType { get; set; }
		/// <summary>
		/// Item Specification for this item.
		/// </summary>
		public Guid Specification { get; set; }
		/// <summary>
		/// Last modified date/time
		/// </summary>
		public DateTime LastModified { get; set; }
		/// <summary>
		/// Href for item path
		/// </summary>
		public Uri Href { get; set; }
		/// <summary>
		/// Gets or sets the security claim id.
		/// </summary>
		/// <value>The security claim id.</value>
        public Guid ItemClaimId { get; set; }

		[XmlIgnore()]
		[NonSerialized()]
		ItemProperty[] m_Properties;

		/// <summary>
		/// Gets or sets the properties.
		/// </summary>
		/// <value>The properties.</value>
		public IEnumerable<IItemProperty> Properties
		{
			get
			{
				if (m_Properties == null)
					return new List<IItemProperty>().AsEnumerable();
				else
					return m_Properties.Cast<IItemProperty>();
			}
			set { m_Properties = value.ToStruct().ToArray(); }
		}

		[XmlIgnore()]
		[NonSerialized()]
		ItemClaim[] m_AccessClaims;


		/// <summary>
		/// Gets or sets the access claims.
		/// </summary>
		/// <value>The access claims.</value>
		public IEnumerable<IItemClaim> AccessClaims
		{
			get
			{
				if (m_AccessClaims == null)
					return new List<IItemClaim>().AsEnumerable();
				else
					return m_AccessClaims.Cast<IItemClaim>();
			}
			set { m_AccessClaims = value.ToStruct().ToArray(); }
		}

		[XmlIgnore()]
		[NonSerialized()]
		ItemRelationship[] m_Relationships;

		/// <summary>
		/// Relationships owned by this item
		/// </summary>
		public IEnumerable<IItemRelationship> Relationships
		{
			get
			{
				if (m_Relationships == null)
					return new List<IItemRelationship>().AsEnumerable();
				else
					return m_Relationships.Cast<IItemRelationship>();
			}
			set { m_Relationships = value.ToStruct().ToArray(); }
		}
	}

	public static partial class Extensions
	{
		/// <summary>
		/// Converts an enumerable set of IItemInstance to a simple structure implementation of the interface
		/// </summary>
		/// <param name="itemInstances"></param>
		/// <returns>An enumerable collection of Item Instance structures.</returns>
		public static IEnumerable<ItemInstance> ToStruct(this IEnumerable<IItemInstance> itemInstances)
		{
			foreach (var item in itemInstances)
			{
				yield return item.ToStruct();
			}
			yield break;
		}

		/// <summary>
		/// Converts an IItemInstance to a simple structure that implements the interface.
		/// </summary>
		/// <param name="item">an IItemInstance to convert into the ItemInstance struct</param>
		/// <returns>a struct that implements IItemInstance</returns>
		public static ItemInstance ToStruct(this IItemInstance item)
		{
			if (item == null)
				throw new ArgumentNullException("item");

			// if the item passed in is already an ItemInstance (struct) then return.
			if (item is ItemInstance)
				return (ItemInstance)item;

			ItemInstance itemInstance = new ItemInstance();
			itemInstance.AccessClaims = item.AccessClaims;
			itemInstance.Comment = item.Comment;
			itemInstance.CreatedBy = item.CreatedBy;
			itemInstance.ExternalId = item.ExternalId;
			itemInstance.Id = item.Id;
			itemInstance.LastModified = item.LastModified;
			itemInstance.LeftVersion = item.LeftVersion;
			itemInstance.MimeType = item.MimeType;
			itemInstance.Name = item.Name;
			itemInstance.ParentId = item.ParentId;
			itemInstance.Properties = item.Properties;
			itemInstance.Published = item.Published;
			itemInstance.Relationships = item.Relationships;
			itemInstance.Specification = item.Specification;
			itemInstance.RightVersion = item.RightVersion;
			itemInstance.Version = item.Version;
			itemInstance.Href = item.Href;
			itemInstance.ItemClaimId = item.ItemClaimId;
			return itemInstance;
		}
	}
}
